#include "Thread.hpp"
#include "LockGuard.hpp"
#include <unistd.h>
#include <vector>

using namespace ThreadModule;

class ThreadData
{
public:
    ThreadData(int& tickets, const std::string &name, pthread_mutex_t &mutex) 
        : _tickets(tickets), _name(name), _total(0), _mutex(mutex)
    {
    }
    ~ThreadData()
    {
    }

public:
    int &_tickets; // 所有线程最后都会引用同一个全局的g_tickets
    int _total;
    std::string _name;
    pthread_mutex_t& _mutex;
};

// 定义一把锁
pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;

int g_tickets = 10000;

// void route(ThreadData *td)
// {
//     while (true)
//     {
//         // 加锁保护临界区资源
//         // pthread_mutex_lock(&gmutex); // 加锁 : 竞争锁是自由竞争的，竞争所的能力太强的线程，会导致其它线程抢不到锁 --- 造成了其他线程的饥饿问题！
//         pthread_mutex_lock(&td->_mutex); // 转而加局部的锁
//         if (td->_tickets > 0)
//         {
//             // 模拟一次抢票逻辑
//             usleep(1000);
//             printf("%s running , get tickets : %d\n", td->_name.c_str(), td->_tickets);
//             td->_tickets--;
//             pthread_mutex_unlock(&td->_mutex); // 解锁
//             td->_total++;
//         }
//         else
//         {
//             pthread_mutex_unlock(&td->_mutex); // 解锁
//             break;
//         }
//     }
// }
// RAII风格的加锁和解锁
void route(ThreadData *td)
{
    while (true)
    {
        // 加锁保护临界区资源
        LockGuard guard(&td->_mutex); // 临时对象,会自动构造和销毁， RAII风格的加锁和解锁
        // td->_mutex.lock();
        // std::lock_guard<std::mutex> lock(td->_mutex);
        if (td->_tickets > 0)
        {
            // 模拟一次抢票逻辑
            usleep(1000);
            printf("%s running , get tickets : %d\n", td->_name.c_str(), td->_tickets);
            td->_tickets--;
            // td->_mutex.unlock();
            td->_total++;
        }
        else
        {
            // td->_mutex.unlock();
            break;
        }
    }
}

const int num = 4;
int main()
{
    pthread_mutex_t mutex; // 定义一个局部的锁
    pthread_mutex_init(&mutex, nullptr); // 初始化锁
    // std::mutex mutex;


    std::vector<Thread<ThreadData *>> threads;
    std::vector<ThreadData *> datas;

    // 1、创建一批线程
    for (int i = 0; i < num; i++)
    {
        std::string name = "thread-" + std::to_string(i + 1);
        ThreadData *td = new ThreadData(g_tickets, name, mutex);
        threads.emplace_back(route, td, name);
        datas.emplace_back(td);
    }

    // 2、启动一批线程
    for (auto &thread : threads)
    {
        thread.Start();
    }

    // 3、等待一批线程
    for (auto &thread : threads)
    {
        thread.Join();
        // std::cout << "wait thread done, thread is : " << thread.name() << std::endl;
    }

    // 4、输出统计数据
    for (auto data : datas)
    {
        std::cout << data->_name << " : " << data->_total << std::endl;
        delete data;
    }

    pthread_mutex_destroy(&mutex); // 释放锁
    return 0;
}

// void print(int &cnt)
// {
//     while (cnt)
//     {
//         std::cout << "hello I am myself thread, cnt: " << cnt-- << std::endl;
//         sleep(1);
//     }
// }

// void print(int &cnt)
// {
//     while (cnt)
//     {
//         std::cout << "hello I am myself thread, cnt: " << cnt-- << std::endl;
//         sleep(1);
//     }
// }

// int main()
// {
//     int num = 10;
//     Thread<int> t1(print, num, "TestThread");
//     t1.Start();
//     std::cout << "name : " << t1.name() << std::endl;

//     t1.Join();

//     return 0;
// }